#ifndef UM_SOCKET_H
#define UM_SOCKET_H

#include <string>

namespace UM
{


class Socket {

public:

	Socket() {
		this->sock = INVALID_SOCKET;
		this->port = -1;
	}

	Socket(const std::string & host, int port) {
		this->sock = INVALID_SOCKET;
		this->host = host;
		this->port = port;
	}

	void setHost(const std::string & host) {
		this->host = host;
	}

	std::string getHost() const {
		return this->host;
	}

	void setPort(int port) {
		this->port = port;
	}

	int getPort() const {
		return this->port;
	}

	bool connect() {
		if (this->sock != INVALID_SOCKET) {
			return false;
		}
		this->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (this->sock == INVALID_SOCKET) {
			return false;
		}

		struct sockaddr_in address;
		address.sin_family = AF_INET;
		address.sin_addr.s_addr = inet_addr(this->host.c_str());
		if (address.sin_addr.s_addr == INADDR_NONE) {
			struct hostent * hostEntry = gethostbyname(this->host.c_str());
			if (hostEntry == 0) {
				return false;
			}
			memcpy(&address.sin_addr, hostEntry->h_addr_list[0], sizeof(struct in_addr));
		}
		address.sin_port = htons(this->port);
		return ::connect(this->sock, (const struct sockaddr *)&address, sizeof(struct sockaddr)) == 0;
	}

	bool close() {
		closesocket(this->sock);
		this->sock = INVALID_SOCKET;
		return true;
	}

	int read(void * buffer, int length) {
		return ::recv(this->sock, (char *)buffer, length, 0);
	}

	int send(const void * buffer, int length) {
		return ::send(this->sock, (const char *)buffer, length, 0);
	}

private:

	SOCKET sock;
	std::string host;
	int port;

};


} // namespace UM


#endif /* UM_SOCKET_H */
